package com.admin.utils.pay.wx;

import com.admin.utils.client.HttpClient;
import com.admin.utils.encrypt.aes.AesCbcUtil;
import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.util.SignUtils;
import com.github.wxpay.sdk.WXPayUtil;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author kuaiting
 * @date 2021/12/20
 * @apiNote
 */
@Component
public class WeixinUtil {



	/**
	 * 使用 weixin-java-pay sdk调用微信支付
	 *
	 * @param appid        微信APPID
	 * @param money        支付金额
	 * @param notifyurl    异步通知地址
	 * @param openid       微信支付用户的openId
	 * @param wxPayService 支付服务
	 * @return Map<String, String> 支付配置信息
	 */

	public static Map<String, String> getPayConfigMap(String appid, String money, String notifyurl, String openid, String body, WxPayService wxPayService) {
		WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
		orderRequest.setSignType(WxPayConstants.SignType.MD5);
		orderRequest.setBody(body);
		//自己生成order_No
		orderRequest.setOutTradeNo(WXPayUtil.generateNonceStr());
		orderRequest.setTradeType(WxPayConstants.TradeType.JSAPI);
		//直接分
		orderRequest.setTotalFee(BaseWxPayRequest.yuanToFen(money));
		// 获取微信支付用户的openId
		orderRequest.setOpenid(openid);
		orderRequest.setSpbillCreateIp("217.0.0.1");
		orderRequest.setNotifyUrl(notifyurl);
		WxPayUnifiedOrderResult wxPayUnifiedOrderResult = null;
		try {
			wxPayUnifiedOrderResult = wxPayService.unifiedOrder(orderRequest);
		} catch (WxPayException e) {
			e.printStackTrace();
			throw new RuntimeException("微信支付调起失败！");
		}


		//组合参数构建支付
		Map<String, String> paySignInfo = new HashMap<>(5);
		String timeStamp = createTimestamp();
		String nonceStr = String.valueOf(System.currentTimeMillis());
		paySignInfo.put("appId", appid);
		paySignInfo.put("nonceStr", nonceStr);
		paySignInfo.put("timeStamp", timeStamp);
		paySignInfo.put("signType", "MD5");
		paySignInfo.put("package", "prepay_id=" + wxPayUnifiedOrderResult.getPrepayId());

		//老版本使用的的签名工具
		//String paySign = SignUtils.createSign(paySignInfo, "MD5", mchkey, false);

		String[] ignoredParams = new String[10];
		String paySign = SignUtils.createSign(paySignInfo, "MD5", wxPayService.getConfig().getMchKey(), ignoredParams);
		paySignInfo.put("paySign", paySign);

		return paySignInfo;
	}

	/**
	 * 使用wxpay-sdk 调用支付
	 *
	 * @param openid    微信OpenId
	 * @param appid     小程序Appid
	 * @param mchid     微信商户号
	 * @param money     支付金额
	 * @param ip        Ip地址
	 * @param mchkey    商户号apikey
	 * @param body      备注信息
	 * @param notifyurl 回调地址
	 * @param url       微信统一下单接url
	 * @return Map<String, String> 支付配置信息
	 * @throws Exception 发生异常抛出的异常信息
	 */
	public static Map<String, String> getPayConfigMap(String openid, String appid, String mchid, String money, String ip, String mchkey, String body, String notifyurl, String url) throws Exception {

		BigDecimal multiply = new BigDecimal(money).multiply(new BigDecimal("100"));
		double v = Double.parseDouble(multiply.toString());
		String tmpmony = Integer.toString((int) v);
		Map<String, String> param = new TreeMap<>();
		//小程序AppId号
		param.put("appid", appid);
		//商户号
		param.put("mch_id", mchid);
		//随机字符串
		param.put("nonce_str", WXPayUtil.generateNonceStr());
		//商品描述
		param.put("body", body);

		String orderNo = WXPayUtil.generateNonceStr();
		//商户订单号
		param.put("out_trade_no", orderNo);
		//总金额（分）
		param.put("total_fee", tmpmony);
		//IP
		param.put("spbill_create_ip", ip);
		//回调地址
		param.put("notify_url", notifyurl);

		param.put("attach", orderNo);
		//交易类型
		param.put("trade_type", "JSAPI");
		param.put("openid", openid);

		String xmlParam = WXPayUtil.generateSignedXml(param, mchkey);
		HttpClient httpClient = new HttpClient(url);
		httpClient.setHttps(true);
		httpClient.setXmlParam(xmlParam);
		httpClient.post();
		String result = httpClient.getContent();

		Map<String, String> map = WXPayUtil.xmlToMap(result);
		String resultCode = map.get("result_code");
		if ("SUCCESS".equals(resultCode)) {
			// 日期格式化
			SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			Date date = new Date();
			String format = dateFormat.format(date);
			// 时间戳
			long d = dateFormat.parse(format, new ParsePosition(0)).getTime() / 1000;
			Map<String, String> paramSign = new TreeMap<>();
			paramSign.put("appId", appid);
			//时间戳
			paramSign.put("timeStamp", Long.toString(d));
			paramSign.put("package", "prepay_id=" + map.get("prepay_id"));
			//随机字符串
			paramSign.put("nonceStr", map.get("nonce_str"));
			paramSign.put("signType", "MD5");

			//生成二次签名
			// 生成签名
			String paySign = WXPayUtil.generateSignature(paramSign, mchkey);

			Map<String, String> paramMap = new TreeMap<>();
			paramMap.put("appId", appid);
			//随机字符串
			paramMap.put("timeStamp", Long.toString(d));
			//随机字符串
			paramMap.put("nonceStr", map.get("nonce_str"));
			paramMap.put("package", "prepay_id=" + map.get("prepay_id"));
			//随机字符串
			paramMap.put("signType", "MD5");
			//调起支付接口 签名
			paramMap.put("paySign", paySign);

			return paramMap;
		} else {
			HashMap<String, String> hashMap = new HashMap<>();
			hashMap.put("code", "500");
			hashMap.put("msg", "下单失败");
			hashMap.put("data", "");
			return hashMap;
		}

	}


	/**
	 * 时间
	 *
	 * @return 时间戳
	 */
	public static String createTimestamp() {
		return Long.toString(System.currentTimeMillis() / 1000);
	}

	/**
	 * 时间戳
	 *
	 * @return
	 */
	public static String getDate() {
		// 日期格式化
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date date = new Date();
		String format = dateFormat.format(date);
		// 时间戳
		long d = dateFormat.parse(format, new ParsePosition(0)).getTime() / 1000;
		return Long.toString(d);
	}


	public static String getUserInfo(String iv, String sessionKey,String encryptedData) {
		String result = null;
		try {
			result = AesCbcUtil.decrypt(encryptedData, sessionKey, iv, "UTF-8");
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

	public static Map<String, String> getOpenId(String code, String appid, String appSecret) throws IOException, ParseException {
		 String url = "https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code";

		String reqUrl = url.replace("APPID", appid);
		reqUrl = reqUrl.replace("SECRET", appSecret);
		reqUrl = reqUrl.replace("JSCODE", code);
		HttpClient httpClient = new HttpClient(reqUrl);
		httpClient.setHttps(true);
		httpClient.get();
		String content = httpClient.getContent();
		JSONObject json = JSONObject.parseObject(content);
		String openid = json.getString("openid");
		String sessionKey = json.getString("session_key");
		Map<String, String> map = new HashMap<>(2);
		map.put("openId", openid);
		map.put("sessionKey", sessionKey);

		return map;
	}


	////////////////////////////////       微信扫码登录配置信息             ///////////////////////////////////////////


	/**
	 * 获取随机字符串
	 */

	public static String getRandomString(int length) {
		String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
		Random random = new Random();
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < length; i++) {
			int number = random.nextInt(62);
			sb.append(str.charAt(number));
		}
		return sb.toString();
	}

	//////////////////////////// 微信网页授权（H5）    /////////////////////////////////////////////

	public static String getWeixinH5Code(String appid, String appSecret, String redirectUrl, String scope) throws IOException, ParseException {
		if (scope == null) {
			scope = "snsapi_userinfo";
		}

		String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect";

		return url
				.replace("APPID", appid)
				.replace("SECRET", appSecret)
				.replace("REDIRECT_URI", redirectUrl)
				.replace("SCOPE", scope).replace("STATE", getRandomString(20)).trim();
	}

	public static Map<String, Object> getWxH5AccessToken(String appid, String appSecret, String code) {
		String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
		String newurl = url
				.replace("APPID", appid)
				.replace("SECRET", appSecret)
				.replace("CODE", code).trim();
		JSONObject jsonObject = JSONObject.parseObject(HttpClient.get(newurl));

		Map<String, Object> map = new HashMap<>();
		map.put("access_token", jsonObject.get("access_token"));
		map.put("expires_in", jsonObject.get("expires_in"));
		map.put("refresh_token", jsonObject.get("refresh_token"));
		map.put("openid", jsonObject.get("openid"));
		map.put("scope", jsonObject.get("scope"));
		return map;
	}

	public static JSONObject getH5UserInfo(String accesstoken, String openid) throws Exception {
		String url = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
		String newurl = url
				.replace("ACCESS_TOKEN", accesstoken)
				.replace("OPENID", openid).trim();
		return JSONObject.parseObject(HttpClient.get(newurl));


	}


	/**
	 * 电脑端微信网页扫码授权登录有2种方式：
	 * 第一种：基于微信公众号，单独获取登录二维码扫码，然后扫码登录，程序控制跳转逻辑，例如CSDN
	 * 第二种：基于微信开放平台，跳转到微信二维码页面进行扫码登录，重定向到成功页面，例如有道笔记
	 */


	public static String getAccessToken(String appid, String appSecret) {
		String tokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=SECRET";
		String newurl = tokenUrl
				.replace("APPID", appid)
				.replace("SECRET", appSecret);
		try {
			HttpClient httpClient = new HttpClient(newurl);
			httpClient.setHttps(true);
			httpClient.post();
			String result = httpClient.getContent();
			JSONObject jsonObject = JSONObject.parseObject(result);
			return jsonObject.getString("access_token");
		} catch (Exception e) {
			e.printStackTrace();
			return "";
		}


	}


	public static Map<String, Object> getTicket(String appid, String appSecret) {
		String accessToken = getAccessToken(appid, appSecret);
		String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + accessToken.trim();
		JSONObject jsonObject = new JSONObject();
		JSONObject actionInfo = new JSONObject();
		JSONObject scene = new JSONObject();
		scene.put("scene_str", getRandomString(20));
		actionInfo.put("scene", scene);
		jsonObject.put("expire_seconds", "604800");
		jsonObject.put("action_name", "QR_STR_SCENE");
		jsonObject.put("action_info", actionInfo);
		String json = HttpClient.sendJson(url, jsonObject.toString());
		JSONObject resJson = JSONObject.parseObject(json);
		Map<String, Object> map = new HashMap<>();
		map.put("ticket", resJson.get("ticket").toString());
		map.put("expire_seconds", resJson.get("expire_seconds").toString());
		map.put("url", resJson.get("url").toString());
		return map;
	}
}
